using System;
using System.Collections.Generic;
using System.Text;
using DslModeling = global::Microsoft.VisualStudio.Modeling;
using DslDesign = global::Microsoft.VisualStudio.Modeling.Design;
using Microsoft.VisualStudio.Modeling.Design;
using System.ComponentModel;
using Microsoft.VisualStudio.Modeling;
using Microsoft.VisualStudio.Modeling.Validation;

namespace Evaluant.EussDSL
{
    /// <summary>
    /// Additional costom behaviors for an Entity. This allows the designer to
    /// be aware of value modifications.
    /// </summary>
    [ValidationState(ValidationState.Enabled)]
    public partial class Entity
    {
        ///// <summary>
        ///// Constructor
        ///// </summary>
        ///// <param name="store">Store where new element is to be created.</param>
        ///// <param name="propertyAssignments">List of domain property id/value pairs to set once the element is created.</param>
        //public Entity(DslModeling::Store store, params DslModeling::PropertyAssignment[] propertyAssignments)
        //    : this(store != null ? store.DefaultPartition : null, propertyAssignments)
        //{
        //    if (string.IsNullOrEmpty(table))
        //    {

        //    }
        //}
        
        ///// <summary>
        ///// Constructor
        ///// </summary>
        ///// <param name="partition">Partition where new element is to be created.</param>
        ///// <param name="propertyAssignments">List of domain property id/value pairs to set once the element is created.</param>
        //public Entity(DslModeling::Partition partition, params DslModeling::PropertyAssignment[] propertyAssignments)
        //    : base(partition, propertyAssignments)
        //{
        //    if (string.IsNullOrEmpty(table))
        //    {

        //    }
        //}

        internal sealed partial class tablePropertyHandler
        {
            protected override void OnValueChanged(Entity element, string oldValue, string newValue)
            {
                if (!element.Store.InUndoRedoOrRollback)
                {
                    if (string.IsNullOrEmpty(newValue))
                    {
                        throw new ArgumentOutOfRangeException("Table", "Table cannot be empty or null.");
                    }
                }
                base.OnValueChanged(element, oldValue, newValue);
                InheritanceDetector.DetectAndShow(element);
            }
        }

        internal sealed partial class typePropertyHandler
        {
            protected override void OnValueChanged(Entity element, string oldValue, string newValue)
            {
                if (!element.Store.InUndoRedoOrRollback)
                {
                    if (string.IsNullOrEmpty(newValue))
                    {
                        throw new ArgumentOutOfRangeException("Type", "Type cannot be empty or null.");
                    }
                }
                base.OnValueChanged(element, oldValue, newValue);
                InheritanceDetector.DetectAndShow(element);

                if (string.IsNullOrEmpty(element.table))
                {
                    element.table = newValue;
                }
            }
        }

        internal sealed partial class copyNodePropertyHandler
        {
            protected override void OnValueChanged(Entity element, string oldValue, string newValue)
            {
                base.OnValueChanged(element, oldValue, newValue);
                InheritanceDetector.DetectAndShow(element);
            }
        }

        internal sealed partial class discriminatorFieldPropertyHandler
        {
            protected override void OnValueChanged (Entity element, string oldValue, string newValue)
            {
                base.OnValueChanged(element, oldValue, newValue);
                InheritanceDetector.DetectAndShow(element);
            }
        }

        internal sealed partial class discriminatorValuePropertyHandler
        {
            protected override void OnValueChanged(Entity element, string oldValue, string newValue)
            {
                base.OnValueChanged(element, oldValue, newValue);
                InheritanceDetector.DetectAndShow(element);
            }
        }

        [ValidationMethod(ValidationCategories.Menu | ValidationCategories.Save)]
        private void DiscriminatorFieldOrCopyNode(ValidationContext context)
        {
            bool discriminatorFieldFilled = !string.IsNullOrEmpty(discriminatorField);
            bool discriminatorValueFilled = !string.IsNullOrEmpty(discriminatorValue);
            bool copyNodeFilled = !string.IsNullOrEmpty(copyNode);
            if (discriminatorFieldFilled && copyNodeFilled)
            {
                context.LogWarning("Entity '" + type + "' has a 'discriminator-field' value and a 'copyNode' value. This can result in an invalid inheritance relation.", "002", this);
            }
            if (discriminatorFieldFilled ^ discriminatorValueFilled)
            {
                context.LogWarning("Entity '" + type + "' should have both 'discriminator-field' and 'discriminator-value' properties filled, or none.", "003", this);
            }
        }

        [ValidationMethod(ValidationCategories.Menu | ValidationCategories.Save)]
        private void UniqueFields(ValidationContext context)
        {
            foreach (Identifier id in Identifiers)
            {
                if (Identifiers.FindAll(delegate(Identifier id_tmp) { return id_tmp.field == id.field; }).Count > 1)
                {
                    context.LogWarning("Entity '" + type + "' has several identifiers with the same field '" + id.field + "'. This should never happen.", "004", this);
                }
            }
        }

        [ValidationMethod(ValidationCategories.Menu | ValidationCategories.Save)]
        private void UniqueAttributeName(ValidationContext context)
        {
            foreach (ModelAttribute ma in Attributes)
            {
                if (Attributes.FindAll(delegate(ModelAttribute ma_tmp) { return ma.name == ma_tmp.name; }).Count > 1)
                {
                    context.LogError("Entity '" + type + "' has several attributes with the same name '" + ma.name + "'. This should never happen.", "018", this);
                }
            }
        }

        [ValidationMethod(ValidationCategories.Menu | ValidationCategories.Save)]
        private void UniqueRealFields(ValidationContext context)
        {
            List<string> RealFields = new List<string>();
            foreach (ModelAttribute ma in Attributes)
            {
                if (string.IsNullOrEmpty(ma.field))
                {
                    RealFields.Add(ma.name);
                }
                else
                {
                    RealFields.Add(ma.field);
                }
            }

            //foreach (ReferenceNew rn in ReferencesNew)
            //{
            //    RealFields.Add(rn.paren
            //}

            foreach (string realField in RealFields)
            {
                if (RealFields.FindAll(delegate(string realField_tmp) { return realField_tmp == realField; }).Count > 1)
                {
                    context.LogError("Entity '" + type + "' has several fields with the same name '" + realField + "'. This should never happen (the 'field' value is implicitly the 'name' value when 'field' is not filled).", "019", this);
                }
            }
        }

        [ValidationMethod(ValidationCategories.Menu | ValidationCategories.Save)]
        private void EntityChildPresent(ValidationContext context)
        {
            foreach (ReferenceNew rn in ReferencesNew)
            {
                if (ReferencesNew.FindAll(delegate(ReferenceNew rn_tmp) { return rn_tmp.name == rn.name; }).Count > 1)
                {
                    context.LogError("The entity '" + type + "' has several References with name '" + rn.name + "'.", "026", this);
                }
            }
        }

        [ValidationMethod(ValidationCategories.Menu | ValidationCategories.Save)]
        private void UniqueDiscriminatorInReferences(ValidationContext context)
        {
            foreach (ReferenceNew rn in ReferencesNew)
            {
                if (ReferencesNew.FindAll(delegate(ReferenceNew rn_tmp) { return rn.discriminatorField == rn_tmp.discriminatorField; }).Count > 1)
                {
                    context.LogError("The entity '" + type + "' contains several References having '" + rn.discriminatorField + "' as discriminatorField. This would result in fields with the same name.", "028", this);
                }
            }
        }
    }
}
